package com.songtech.base.redis;

import java.lang.reflect.Method;

import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;

import redis.clients.jedis.JedisPoolConfig;


/**
 * 
 * spring redis配置
 */
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport implements EnvironmentAware{

	Logger logger = LoggerFactory.getLogger(RedisConfig.class);
	
	private RelaxedPropertyResolver propertyResolver;
	
	
	 /**
	  * 定义缓存数据 key生成策略
      * 包名+类名+方法名+所有参数 
	  */  
	@Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append(obj == null ? "null" : obj.toString());
                }
                return sb.toString();
            }
        };
    }
	
	/**
	 * jedis配置
	 * @return
	 */
	@Bean
    public JedisPoolConfig getRedisConfig() {
        JedisPoolConfig config = new JedisPoolConfig();
        //最大空闲连接
        config.setMaxIdle(Integer.parseInt(propertyResolver.getProperty("maxIdle").trim()));
        //最大阻塞等待时间
        config.setMaxWaitMillis(Integer.parseInt(propertyResolver.getProperty("maxWait").trim()));
        //在获取连接的时候检查有效性
        config.setTestOnBorrow(true);
        return config;
    }
	
	/**
	 * redis服务注册
	 * @return
	 */
	@Bean
	public JedisConnectionFactory getConnectionFactory() {
         JedisConnectionFactory factory = new JedisConnectionFactory();
         JedisPoolConfig config = getRedisConfig();
         factory.setPoolConfig(config);
         factory.setHostName(propertyResolver.getProperty("host"));
         /**redis端口*/
         factory.setPort(Integer.parseInt(propertyResolver.getProperty("port").trim()));
         /**连接超时时间*/
         factory.setTimeout(Integer.valueOf(propertyResolver.getProperty("conn.timeout").trim()));
         factory.setDatabase(Integer.valueOf(propertyResolver.getProperty("default.db").trim()));
         logger.info("JedisConnectionFactory bean init success.");
         return factory;
     }
	
	
	/**
	 * 
	 * redisTemplate 序列化配置
	 * @param connectionFactory
	 * @return
	 */
   @SuppressWarnings({ "unchecked", "rawtypes" })
   @Bean(name="redisTemplate")
   public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) {


      RedisTemplate template = new RedisTemplate();
      template.setConnectionFactory(connectionFactory);

//       template.setKeySerializer(new StringRedisSerializer());
//       template.setHashKeySerializer(new StringRedisSerializer());
//       template.setHashValueSerializer(new JdkSerializationRedisSerializer());
//       template.setValueSerializer(new JdkSerializationRedisSerializer());
//       template.setConnectionFactory(connectionFactory);

      /**使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值*/
      Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
       ObjectMapper mapper = new ObjectMapper();
       mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
       mapper.registerModule(new JavaTimeModule());
       mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
       mapper.enableDefaultTyping();
       mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

       serializer.setObjectMapper(mapper);


      template.setValueSerializer(serializer);
      /**使用StringRedisSerializer来序列化和反序列化redis的key值*/
      template.setKeySerializer(new StringRedisSerializer());
      template.afterPropertiesSet();
      return template;
   }
   
   /**
    * redis交给cacheManager管理
    * @param redisTemplate
    * @return
    */
   @Bean  
   public CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate) {  
       RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
       /**设置默认缓存时间*/
       rcm.setDefaultExpiration(Long.valueOf(propertyResolver.getProperty("defaultCacheExpireTime").trim()));
       return rcm;  
   }  
   
	@Override
	public void setEnvironment(Environment environment) {
		this.propertyResolver = new RelaxedPropertyResolver(environment,"redis.");
	}
}
